#import "BWGridLayer.h"

#import "BWGridGeometry.h"
#import "BWGridAttributes.h"

static NSColor *g_lighterGray;

@implementation BWGridLayer

+ (void) initialize
{
    [super initialize];
    
    [BWGridLayer setVersion: 1];

} // initialize


- (id) init
{
    if (self = [super init]) {
        g_lighterGray = [NSColor colorWithDeviceWhite: 0.8
                                 alpha: 1.0];
        [g_lighterGray retain];
    }

    return (self);

} // init


typedef void (*lineDrawProc) (NSPoint start, NSPoint end, 
                              BWGridAttributes *attributes);

void drawHeavyLine (NSPoint start, NSPoint end,
                    BWGridAttributes *attributes)
{
    [NSBezierPath setDefaultLineCapStyle: NSSquareLineCapStyle];
    [NSBezierPath setDefaultLineWidth: [attributes majorLineWeightPoints]];
    [[attributes majorLineColorColor] set];
    [NSBezierPath strokeLineFromPoint: start  toPoint: end];

} // drawHeavyLine


void drawLightLine (NSPoint start, NSPoint end,
                    BWGridAttributes *attributes)
{
    [NSBezierPath setDefaultLineCapStyle: NSSquareLineCapStyle];
    [NSBezierPath setDefaultLineWidth: [attributes minorLineWeightPoints]];
    [[attributes minorLineColorColor] set];
    [NSBezierPath strokeLineFromPoint: start  toPoint: end];

} // drawLightLine


void drawNothing (NSPoint start, NSPoint end,
                  BWGridAttributes *attributes)
{
} // drawNothing



- (void) drawGridInRect: (NSRect) rect
             lightLines: (lineDrawProc) lightLines
             heavyLines: (lineDrawProc) heavyLines
{
    NSRect bounds;
    bounds = [self bounds];

    // upper-left corner
    NSPoint topLeft;
    topLeft = NSMakePoint (bounds.origin.x,
                           bounds.origin.y + bounds.size.height);

    float x, y;
    int count;

    float originX = bounds.origin.x;
    float originY = bounds.origin.y;

    count = 0;

    // vertical lines
    for (x = originX; x < [geometry width]; x += [geometry cellWidth]) {
        if (x < rect.origin.x || x > rect.origin.x + rect.size.width) {
            count++;
            continue;
        }

        NSPoint start = NSMakePoint (x, originY);
        NSPoint end = NSMakePoint (x, originY + [geometry height]);

        if ((count % [attributes majorLinesEvery]) == 0) {
            (*heavyLines)(start, end, attributes);
        } else {
            (*lightLines)(start, end, attributes);
        }

        if (count >= [geometry countAcross]) {
            break;
        }
        count++;
    }

    // horizontal lines

    count = 0;
    for (y = originY; y < [geometry height]; y += [geometry cellHeight]) {
        if (y < rect.origin.y || y > rect.origin.y + rect.size.height) {
            count++;
            continue;
        }

        NSPoint start = NSMakePoint (originX, y);
        NSPoint end = NSMakePoint (originX + [geometry width], y);

        if ((count % [attributes majorLinesEvery]) == 0) {
            (*heavyLines)(start, end, attributes);
        } else {
            (*lightLines)(start, end, attributes);
        }

        if (count >= [geometry countDown]) {
            break;
        }
        count++;
    }

} // drawGridInRect


// !!! move me to an overlay class
- (void) drawCenterWedges
{
    float midx, midy;
    midx = [geometry width] / 2;
    midy = [geometry height] / 2;

    NSBezierPath *path = [NSBezierPath bezierPath];
    [[NSColor blackColor] set];
    
    // top
    [path moveToPoint: NSMakePoint (midx - [geometry cellWidth] / 2, 0)];
    [path lineToPoint: NSMakePoint (midx + [geometry cellWidth] / 2, 0)];
    [path lineToPoint: NSMakePoint (midx, + [geometry cellHeight] * 1.75)];
    [path closePath];
    [path fill];

    // bottom
    [path removeAllPoints];
    [path moveToPoint: NSMakePoint (midx - [geometry cellWidth] / 2,
                                    [geometry height])];
    [path lineToPoint: NSMakePoint (midx + [geometry cellWidth] / 2, 
                                    [geometry height])];
    [path lineToPoint: NSMakePoint (midx, 
                                    [geometry height] 
                                    - [geometry cellHeight] * 1.75)];
    [path closePath];
    [path fill];

    // left
    [path removeAllPoints];
    [path moveToPoint: NSMakePoint (0, midy - [geometry cellHeight] / 2)];
    [path lineToPoint: NSMakePoint (0, midy + [geometry cellHeight] / 2)];
    [path lineToPoint: NSMakePoint ([geometry cellWidth] * 1.75, midy)];
    [path closePath];
    [path fill];
                                    
    // right
    [path removeAllPoints];
    [path moveToPoint: NSMakePoint ([geometry width], 
                                    midy - [geometry cellHeight] / 2)];
    [path lineToPoint: NSMakePoint ([geometry width], 
                                    midy + [geometry cellHeight] / 2)];
    [path lineToPoint: NSMakePoint ([geometry width] 
                                    - [geometry cellWidth] * 1.75, midy)];
    [path closePath];
    [path fill];

} // drawCenterWedges


- (void) drawRect: (NSRect) rect
{
    if ([attributes showMajorLines]) {
        [self drawGridInRect: [self bounds]
              lightLines: drawLightLine
              heavyLines: drawNothing];
        
        [self drawGridInRect: [self bounds]
              lightLines: drawNothing
              heavyLines: drawHeavyLine];

    } else {
        [self drawGridInRect: [self bounds]
              lightLines: drawLightLine
              heavyLines: drawLightLine];
    }

    // ink in the bottom and right edge
    NSPoint start, end;

    start = NSMakePoint (NSMaxX(rect), NSMinY(rect));
    end = NSMakePoint (NSMaxX(rect), NSMaxY(rect));

    if ([attributes showMajorLines]) {
        drawHeavyLine (start, end, attributes);
    } else {
        drawLightLine (start, end, attributes);
    }

    start = NSMakePoint (NSMinX(rect), NSMaxY(rect));
    end = NSMakePoint (NSMaxX(rect), NSMaxY(rect));

    if ([attributes showMajorLines]) {
        drawHeavyLine (start, end, attributes);
    } else {
        drawLightLine (start, end, attributes);
    }

    [self drawCenterWedges];

} // drawRect


- (BWLayerKind) layerKind
{
    return (kLayerKind_Grid);
} // layerKind


- (void) setGridAttributes: (BWGridAttributes *) a
{
    [attributes removeObserver: self
                forKeyPath: @"gridAttributeChange"];

    [a retain];
    [attributes release];
    attributes = a;

    [attributes addObserver: self
                forKeyPath: @"gridAttributeChange"
                options: NSKeyValueObservingOptionNew
                context: NULL];
    
} // setGridAttributes




- (void) observeValueForKeyPath: (NSString *) keyPath
                       ofObject: (id) object
                         change: (NSDictionary *) change
                        context: (void *) context
{
    [self postChangeNotification];
} // observeValueForKeyPath


- (void) encodeWithCoder: (NSCoder *) coder
{
    [super encodeWithCoder: coder];
    [coder encodeObject: attributes];
    
} // encodeWithCoder


- (id) initWithCoder: (NSCoder *) coder
{
    if (self = [super initWithCoder: coder]) {
        BWGridAttributes *attrs = [coder decodeObject];
        [self setGridAttributes: attrs];
    }

    return (self);

} // initWithCoder


@end // BWGridLayer
